package cn.chenhuanming.shh.authentication.server.security;

import cn.chenhuanming.utils.jwt.JWTSecurityAutoConfiguration;
import cn.chenhuanming.utils.jwt.core.JWTSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CharacterEncodingFilter;

import java.util.Arrays;

/**
 * Created by chenhuanming on 2017-07-08.
 *
 * @author chenhuanming
 */
@Configuration
public class SecurityConfiguration extends JWTSecurityAutoConfiguration {

    @Autowired
    UserServiceDetails userServiceDetails;

    @Autowired
    CorsConfigurationSource corsConfigurationSource;

    @Autowired
    JWTSuccessHandler successHandler;

    @Override
    protected void configureHttpSecurity(HttpSecurity http) throws Exception {
        http
                .cors().and()
                .antMatcher("/**").authorizeRequests()
                .antMatchers("/", "/login**").permitAll()
                .anyRequest().authenticated()
                .and().formLogin().loginPage("/")
                .and().csrf().disable()
                .addFilterBefore(characterEncodingFilter(), CsrfFilter.class)
                .addFilterAt(formAndJSONAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    protected UserDetailsService userDetailsService() {
        return userServiceDetails;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/webjars/**", "/static/**");
    }

    @Override
    @Bean // share AuthenticationManager for web and oauth
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return authenticationManager();
    }

    @Bean
    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return userDetailsService();
    }

    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(userServiceDetails);
        daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
        AuthenticationManager authenticationManager =
                new ProviderManager(Arrays.asList(daoAuthenticationProvider));
        return authenticationManager;
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("*"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Bean
    CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("utf-8");
        characterEncodingFilter.setForceEncoding(true);
        return characterEncodingFilter;
    }

    @Bean
    FormAndJSONAuthenticationFilter formAndJSONAuthenticationFilter() throws Exception {
        FormAndJSONAuthenticationFilter filter = new FormAndJSONAuthenticationFilter();
        filter.setAuthenticationManager(this.authenticationManager());
        filter.setFilterProcessesUrl("/login/self");
        filter.setAuthenticationSuccessHandler(successHandler);
        filter.setAuthenticationFailureHandler(new FailureHandler());
        return filter;
    }

}
